package spectra.ee.web.api.controller;

import java.util.HashMap;
import java.util.Map;

import spectra.base.log.Logger;
import spectra.base.util.StringUtil;
import spectra.base.util.Util;
import spectra.ee.web.api.model.ParameterForm;

/**
 * DispatcherServlet 은 다음과 같은 역할을 합니다. <br />
 * (DispatcherServlet 은 Servlet 객체 request, response 등을 직접적으로 코딩하여 사용하지 않는다.
 * Servlet 관련 코드들은 상위 클래스인 AjaxBaseServlet 에 코딩한다.)
 * - 기본적으로 MVC 패턴의 컨트롤러 역할을 하는 클래스 입니다. <br />
 * - 필요한 초기 설정값을 읽어옵니다.  (web.xml) <br />
 * - 적절한 요청인지 validation 합니다. (인증 포함) <br />
 * - 요청(request)를 받아서, 파라메터를 분석합니다. (key/value or json) <br />
 * - 처리할 로직(클래스의 메소드)을 찾아서 파라메터와 함께 호출합니다. (설정 or 규약) <br />
 * - 결과를 리턴합니다. (데이터 구조 : json) <br />
 * 
 * 변경 가능성이 있는 코드는 인터페이스로 빼고 구현 클래스를 작성합니다. <br />
 *  - 인증, 파라메터 파싱, 로직 클래스 맵핑 <br />
 * 이러한 업무흐름만 가지고 있으며, 실제적인 세부사항은 다른 클래스에서 구현합니다. <br />
 * 예외를 모두 처리하여 에러코드로 클라이언트에 리턴합니다. <br />
 * 
 * 
 * @author dhheo
 *
 */
public class DispatcherServlet extends AjaxBaseServlet 
{
	/**  */
	private static final long serialVersionUID = 1L;
	/** Logger객체. */
    private static Logger logger = Logger.getLoggerInstance(DispatcherServlet.class.getName());
    /** 파라메터값을 파싱한 결과 정보로 부터 필요한 값을 바로 가져오기 위해  */
    protected IParameterMapper paramMapper = null;
    /** 결과를 리턴할 url 맵핑 정보 */
    protected Map resultView = null;
    
	public DispatcherServlet()
	{
		super();
	}
	
	public void init(Map initParameter)
	{
		paramMapper = new ClassMapper();
		String resultURL = (String)initParameter.get("resultURL");
		resultView = this.getUrlMap(resultURL);
	}
	
    /**
     * Business 로직단을 수행한다.
     * 
     * @param ajaxFrom
     * @return
     * @throws Exception
     */
    public Object invokeService(ParameterForm parameterForm) throws Exception
    {
    	Object objResult = null;
		//command 가 맵핑되는 실제method 값을 가져온다.
		String strMethod = paramMapper.getMethodFromMapping(parameterForm.getCommand());
    	Object service = paramMapper.getService(parameterForm.getServiceName());
    	Object model = parameterForm.getForm();
    	
    	logger.debug("method=" + strMethod + ", service=" + parameterForm.getServiceName() + ", form=" + parameterForm.getFormName());
    	//파라메터가 없는경우
    	if (model == null)
    	{
    		objResult = Util.invokeMothod(service, strMethod, null);
    	}
    	else
    	{
    		objResult = Util.invokeMothod(service, strMethod, new Class[]{model.getClass()} ,  new Object[]{ model});
    	}
		
    	return objResult;
    }

	public String getView(String urlPath)
	{
		String view = null;
		logger.debug("urlPath : " + urlPath);
		String defaultView = null;
		
		// * 가 있는 경우 디폴트 값이된다.
		if (resultView.containsKey("*"))
		{
			defaultView = (String)resultView.get("*");
			logger.debug("default view : " + defaultView);
		}
		int iDot = urlPath.lastIndexOf(".") == -1 ? urlPath.length() : urlPath.lastIndexOf(".");  
		String urlKey = urlPath.substring(urlPath.lastIndexOf("/") + 1, iDot);
		logger.debug("url path key : " + urlKey);
		if (resultView.get(urlKey) == null)
		{
			view = defaultView;
		}
		else
		{
			view = (String)resultView.get(urlKey);
		}
		
		logger.debug("view : " + view);
		return view;
	}

	/**
	 * , (쉼표) 로 구분되어있는 각 값을 가져와서 = 로 구분하여 map 에 담아 리턴한다.
	 * 예) *=result.jsp, mail=/m/result.jsp
	 * @param resultURL
	 * @return
	 */
	public Map getUrlMap(String resultURL)
	{
		Map mapUrl = new HashMap();
		String[] urls = resultURL.split(",");
		for (int i = 0; i < urls.length; i++)
		{
			String[] keyAndValue = urls[i].split("=", 2);
			String key = keyAndValue[0].trim();
			String value = keyAndValue[1].trim();
			mapUrl.put(key, value);
		}
		return mapUrl;
	}
	
	public boolean validate(ParameterForm parameterForm)
	{
		return super.validate(parameterForm);
	}
}
